﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Lidgren.Network;
using Microsoft.Xna.Framework;

namespace NetworkDemo
{
    public delegate void NetstatusEventHandler(object sender, NetstatusEventArgs e);

    public class NetstatusEventArgs : EventArgs
    {
        private NetConnectionStatus netStatus;
        public NetstatusEventArgs(NetConnectionStatus curStatus)
        {
            this.netStatus = curStatus;
        }

        public NetConnectionStatus NetStatus
        {
            get { return netStatus; }
        }
    }

    public class NetworkManager
    {
        GameController gameController;
        NetClient client;
        NetConfiguration config;
        bool readMessages = false;
        internal Thread heartbeatThread;

        #region Events
        public event NetstatusEventHandler netstatusEvent;

        protected virtual void OnNetStatusChange(NetstatusEventArgs e)
        {
            if (netstatusEvent != null)
                netstatusEvent(this, e);
        }

        #endregion
        public NetworkManager(GameController theController)
        {
            gameController = theController;
            config = new NetConfiguration("networkdemo");
            client = new NetClient(config);
            client.SetMessageTypeEnabled(NetMessageType.DebugMessage, true);
            client.SetMessageTypeEnabled(NetMessageType.ConnectionRejected, true);
            
        }

        public void ConnectToServer(string serverIP, int serverPort)
        {
            while (client.Status == NetConnectionStatus.Disconnecting)
                Thread.Sleep(1);

            if (client.Status != NetConnectionStatus.Disconnected) return;

            client.Start();
            client.DiscoverKnownServer("85.235.20.111", 1000);

            if (heartbeatThread != null)
            {
                if (heartbeatThread.IsAlive) return;
                heartbeatThread = null;
            }

            heartbeatThread = new Thread(new ThreadStart(Run));
            heartbeatThread.Name = "Network Manager thread";
            heartbeatThread.IsBackground = true;
            readMessages = true;
            heartbeatThread.Start();
        }
        private void Run()
        {
            while (readMessages)
            {
                try
                {
                    Heartbeat();
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Network Manager.Heartbeat() failed: " + ex.Message);
                }

                Thread.Sleep(1);
            }
        }

        public bool SendMessage(string S)
        {
            NetBuffer buffer = client.CreateBuffer();
            buffer.Write(S);
            client.SendMessage(buffer, NetChannel.ReliableUnordered);
            return true;
        }

        public void Heartbeat()
        {
            ReadMessages();
        }

        private void ReadMessages()
        {
            NetBuffer buffer = client.CreateBuffer();
            NetMessageType type;
            while (client.ReadMessage(buffer, out type))
            {
                switch (type)
                {
                    case NetMessageType.ServerDiscovered:
                        // just connect to any server found!

                        // make hail
                        NetBuffer buf = client.CreateBuffer();
                        buf.Write("Hail from " + Environment.MachineName);
                        client.Connect(buffer.ReadIPEndPoint(), buf.ToArray());
                        break;
                    case NetMessageType.ConnectionRejected:
                        Console.WriteLine("Rejected: " + buffer.ReadString());
                        break;
                    case NetMessageType.DebugMessage:
                    case NetMessageType.VerboseDebugMessage:
                        Console.WriteLine(buffer.ReadString());
                        break;
                    case NetMessageType.StatusChanged:
                        OnNetStatusChange(new NetstatusEventArgs(client.Status));
                        break;
                    case NetMessageType.Data:
                        // The server sent this data!
                        gameController.HandleNetworkData(buffer);
                        break;
                }
            }
        }

        #region Public Methods
        public void GetAllPlayerData()
        {
            if (client.Status != NetConnectionStatus.Connected) return;
            NetBuffer buf = client.CreateBuffer();
            buf.Write("allplayers");
            client.SendMessage(buf, NetChannel.ReliableUnordered);
        }

        public void GetClientPlayerID()
        {
            if (client.Status != NetConnectionStatus.Connected) return;
            NetBuffer buf = client.CreateBuffer();
            buf.Write("newplayer");
            client.SendMessage(buf, NetChannel.ReliableUnordered);
        }

        public void PushNetworkUpdate(Player P)
        {
            if (client.Status != NetConnectionStatus.Connected) return;

            NetBuffer buf = client.CreateBuffer();

            buf.Write("update");
            Player.WriteBuffer(P, buf);
            client.SendMessage(buf, NetChannel.ReliableUnordered);
            P.Dirty = false;
        }

        #endregion
    }
}